package com.xtayfjpk.security.certificate;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.math.BigInteger;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.MessageDigest;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import java.security.Signature;
import java.security.cert.CRL;
import java.security.cert.CertPath;
import java.security.cert.CertificateFactory;
import java.security.cert.X509CRL;
import java.security.cert.X509Certificate;
import java.security.cert.X509Extension;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.Certificate;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.cert.X509CRLHolder;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.X509v1CertificateBuilder;
import org.bouncycastle.cert.X509v2CRLBuilder;
import org.bouncycastle.cert.X509v3CertificateBuilder;
import org.bouncycastle.crypto.tls.CertificateRequest;
import org.bouncycastle.crypto.util.SubjectPublicKeyInfoFactory;
import org.bouncycastle.jcajce.provider.keystore.PKCS12;
import org.bouncycastle.jce.PKCS12Util;
import org.bouncycastle.jce.X509Principal;
import org.bouncycastle.jce.X509V2CRLGenerator;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.DefaultSignatureAlgorithmIdentifierFinder;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.bouncycastle.pkcs.PKCS10CertificationRequest;
import org.bouncycastle.pkcs.PKCS10CertificationRequestBuilder;
import org.bouncycastle.x509.X509V3CertificateGenerator;
import org.junit.Test;

import com.xtayfjpk.security.DigestTest;
import com.xtayfjpk.security.utils.SecurityUtils;

public class CertificateTest {

	@Test
	public void testGenerator()  throws Exception {
		//KeyStore keyStore = KeyStore.getInstance("JKS");
		Security.addProvider(new BouncyCastleProvider());
		//keyStore.get
		
		KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
		KeyPair keyPair = keyPairGenerator.generateKeyPair();
		X509V3CertificateGenerator certificateGenerator = new X509V3CertificateGenerator();
		certificateGenerator.setSerialNumber(BigInteger.ONE);
		certificateGenerator.setIssuerDN(new X509Principal("C=CN,ST=李四"));
		certificateGenerator.setNotBefore(new Date());
		certificateGenerator.setNotAfter(new Date(System.currentTimeMillis()+ 10 * 24 * 60 * 60 * 1000));
		certificateGenerator.setSubjectDN(new X509Principal("C=CN,ST=张三"));
		certificateGenerator.setPublicKey(keyPair.getPublic());
		certificateGenerator.setSignatureAlgorithm("MD5WithRSA");
		X509Certificate certificate = certificateGenerator.generate(keyPair.getPrivate());
		
		System.out.println(certificate);
		
		FileOutputStream fos = new FileOutputStream("H:/my.cer");
		fos.write(certificate.getEncoded());
		fos.close();
		
		
		
		Signature signature = Signature.getInstance(certificate.getSigAlgName());
		signature.initVerify(certificate.getPublicKey());
		signature.update(certificate.getTBSCertificate());
		System.out.println(signature.verify(certificate.getSignature()));
		
		
		MessageDigest messageDigest = MessageDigest.getInstance("SHA1");
		byte[] result = messageDigest.digest(certificate.getEncoded());
		System.out.println(SecurityUtils.toHexString(result));
		
		/*signature.update(result);
		System.out.println(signature.verify(certificate.getSignature()));*/
		
	}

	@Test
	public void testBuilder() throws Exception {
		final AlgorithmIdentifier sigAlgId = new DefaultSignatureAlgorithmIdentifierFinder().find("SHA1withRSA");
		KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
		KeyPair keyPair = keyPairGenerator.generateKeyPair();
		X500Name issuer = new X500Name("C=CN,ST=李四");
		BigInteger serial = BigInteger.TEN;
		Date notBefore = new Date();
		Date notAfter = new Date(System.currentTimeMillis()+ 10 * 24 * 60 * 60 * 1000);
		X500Name subject = new X500Name("C=CN,ST=张三");
		SubjectPublicKeyInfo publicKeyInfo = new SubjectPublicKeyInfo(sigAlgId, keyPair.getPublic().getEncoded());
		X509v3CertificateBuilder x509v1CertificateBuilder = new X509v3CertificateBuilder(issuer, serial, notBefore, notAfter, subject, publicKeyInfo);
		
		X509CertificateHolder certificateHolder = x509v1CertificateBuilder.build(new ContentSigner() {
			@Override
			public byte[] getSignature() {
				return "xtayfjpk".getBytes();
			}
			
			@Override
			public OutputStream getOutputStream() {
				return new ByteArrayOutputStream();
			}
			
			@Override
			public AlgorithmIdentifier getAlgorithmIdentifier() {
				return sigAlgId;
			}
		});
		
		Certificate certificate = certificateHolder.toASN1Structure();
		FileOutputStream fos = new FileOutputStream("H:/test.cer");
		fos.write(certificate.getEncoded());
		fos.close();
	}
	
	@Test
	public void testCertPath() throws Exception {
		Security.addProvider(new BouncyCastleProvider());
		CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
		FileInputStream caIn = new FileInputStream("D:\\installations\\gitblit-1.6.0\\data\\certs\\ca.cer");
		java.security.cert.Certificate caCertificate = certificateFactory.generateCertificate(caIn);
		FileInputStream cert181In = new FileInputStream("C:\\Users\\zj\\Desktop\\181.cer");
		java.security.cert.Certificate cert181 = certificateFactory.generateCertificate(cert181In);
		X509Certificate x509Certificate = (X509Certificate) caCertificate;
		Set<String> oids = x509Certificate.getCriticalExtensionOIDs();
		for(String oid : oids) {
			System.out.println("---" + x509Certificate.getExtensionValue(oid));
		}
		
		
		List<java.security.cert.Certificate> list = new ArrayList<>();
		list.add(cert181);
		list.add(caCertificate);
		CertPath certPath = certificateFactory.generateCertPath(list);
		System.out.println(certPath);
		
		System.out.println(certPath.getType());
		
	}
	
	@Test
	public void testWriteCRL() throws Exception {
		File caRevocationList = new File("H:/caRevocationList.crl");
		File caKeyStoreFile = new File("D:\\installations\\gitblit-1.6.0\\data\\certs\\caKeyStore.p12");
		
		KeyStore caKeyStore = KeyStore.getInstance("PKCS12");
		String password = "gitblit";
		FileInputStream caStream = new FileInputStream(caKeyStoreFile);
		caKeyStore.load(caStream, password.toCharArray());;
		caStream.close();
		String caAlias = "Gitblit Certificate Authority";
		PrivateKey caPrivateKey = (PrivateKey) caKeyStore.getKey(caAlias, password.toCharArray());
		System.out.println(caPrivateKey);
		
		CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
		FileInputStream cert181In = new FileInputStream("C:\\Users\\zj\\Desktop\\181.cer");
		X509Certificate cert181 = (X509Certificate) certificateFactory.generateCertificate(cert181In);
		
		X500Name issuerDN = new X500Name(cert181.getIssuerDN().getName());
		X509v2CRLBuilder crlBuilder = new X509v2CRLBuilder(issuerDN, new Date());
		if (caRevocationList.exists()) {
			byte [] data = SecurityUtils.readFileContent(caRevocationList);
			X509CRLHolder crl = new X509CRLHolder(data);
			crlBuilder.addCRL(crl);
		}
		crlBuilder.addCRLEntry(cert181.getSerialNumber(), new Date(), 1);
		ContentSigner contentSigner = new JcaContentSignerBuilder("SHA1WithRSA").build(caPrivateKey);
		X509CRLHolder x509crlHolder = crlBuilder.build(contentSigner);
		
		FileOutputStream crlOut = new FileOutputStream(caRevocationList);
		crlOut.write(x509crlHolder.getEncoded());
		crlOut.close();
	}
	
	@Test
	public void testReadCRL() throws Exception {
		CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
		File caRevocationList = new File("H:/caRevocationList.crl");
		FileInputStream crlIn = new FileInputStream(caRevocationList);
		X509CRL crl = (X509CRL) certificateFactory.generateCRL(crlIn);
		System.out.println(crl.getType());
	}
	
	@Test
	public void testCreateCSR() throws Exception {
		KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
		KeyPair keyPair = generator.generateKeyPair();
		PublicKey publicKey = keyPair.getPublic();
		
		X500Name subject = new X500Name("CN=zhangsan,OU=development,O=Huawei,L=ShenZhen,ST=GuangDong,C=CN");
		
		SubjectPublicKeyInfo publicKeyInfo = new SubjectPublicKeyInfo(
				AlgorithmIdentifier.getInstance(PKCSObjectIdentifiers.rsaEncryption), publicKey.getEncoded());
		PKCS10CertificationRequestBuilder builder = new PKCS10CertificationRequestBuilder(subject, publicKeyInfo);
		
		ContentSigner contentSigner = new JcaContentSignerBuilder("SHA1WithRSA").build(keyPair.getPrivate());
		PKCS10CertificationRequest certificationRequest = builder.build(contentSigner);
		System.out.println(certificationRequest);
		
		
		PKCS10CertificationRequest request = new PKCS10CertificationRequest(certificationRequest.getEncoded());
		
		System.out.println(certificationRequest.equals(request));
		
		//然后获取请求信息，例如，请求者公钥，subject,签名算法等，再使用根证书私钥对其签名
	}
}
